﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Linq;
using System.Collections.Generic;

namespace SGCG.Model
{
    // TODO Porra, o ideal era que a interface de qualquer objeto composto fosse igual [cont...]
    // (agrupamentos, retangulos, triangulos). Mas aí a gente precisaria de um dinamismo que a
    // linguagem não fornece... Ou fornece? Sherman?
    public abstract class CompositeBorderedGraphicObject : GroupBase, IHasBorder, IFillable
    {
        protected CompositeBorderedGraphicObject(GraphicObject parent) : base(parent)
        {
            this.rawGraphicObjects = this.BuildObject().Cast<BorderedGraphicObject>().ToArray();
        }

        protected abstract IEnumerable<GraphicObject> BuildObject();

        protected abstract Point GetBarycenter();

        protected BorderedGraphicObject FirstObject
        {
            get { return this.GraphicObjects.First(); }
        }

        protected IEnumerable<BorderedGraphicObject> GraphicObjects
        {
            get { return (BorderedGraphicObject[])this.rawGraphicObjects; }
        }

        public LineStyle LineStyle
        {
            get
            {
                return this.FirstObject.LineStyle;
            }
            set
            {
                this.GraphicObjects.Each(graphicObject => graphicObject.LineStyle = value);
            }
        }

        public LineThickness LineThickness
        {
            get
            {
                return this.FirstObject.LineThickness;
            }
            set
            {
                this.GraphicObjects.Each(graphicObject => graphicObject.LineThickness = value);
            }
        }

        public Color Color
        {
            get
            {
                return this.FirstObject.Color;
            }
            set
            {
                this.GraphicObjects.Each(graphicObject => graphicObject.Color = value);
            }
        }

        private FillType fill;
        public FillType Fill
        {
            get { return fill; }
            set
            {
                fill = value;
                RaiseGraphicPropertyChanged("Fill");
            }
        }

        private Color fillColor;
        public Color FillColor
        {
            get { return fillColor; }
            set
            {
                fillColor = value;
                RaiseGraphicPropertyChanged("FillColor");
            }
        }

        public Color OriginalColor { get { return FirstObject.OriginalColor; } }

        protected void CopyProperties(CompositeBorderedGraphicObject other)
        {
            base.CopyProperties(other);
            other.LineStyle = LineStyle;
            other.LineThickness = LineThickness;
            other.Color = OriginalColor;
            other.Fill = Fill;
            other.FillColor = FillColor;
        }

        private void DrawFill()
        {
            if (Fill != FillType.None)
            {
                FloodPainter painter = new FloodPainter(DrawingCanvas.GetWidth(), DrawingCanvas.GetHeight());
                GraphicObjects.Each(g =>
                {
                    GraphicObject newGraphic = g.CreateCopy();
                    newGraphic.Parent = this;
                    if (newGraphic is IHasBorder)
                        (newGraphic as IHasBorder).LineStyle = Model.LineStyle.Normal;
                    if (newGraphic is IFillable)
                        (newGraphic as IFillable).Fill = FillType.None;
                    newGraphic.Attach(painter.FakeCanvas);
                    newGraphic.Draw();
                });
                painter.DrawingCanvas = DrawingCanvas;
                painter.Texture = TextureFactory.CreateTexture(Fill, FillColor);
                Point gg = GetBarycenter();
                painter.Draw((int)Math.Round(gg.X), (int)Math.Round(gg.Y));
            }
        }

        public override void Draw()
        {
            DrawFill();
            base.Draw();
        }
    }
}
